/* libfake437 - a library for the rendering of code page 437 `graphics'
 * Copyright (C) 2008 Jack Kelly <endgame.dos@gmail.com>
 *
 * This program is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation, either version 3 of
 * the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif

#include <stdio.h>
#ifdef HAVE_STDLIB_H
#  include <stdlib.h>
#endif
#include <SDL.h>
#include "fake437.h"

/* As seen in the SDL examples */
static void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel){
  int bpp = surface->format->BytesPerPixel;
  /* Here p is the address to the pixel we want to set */
  Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
  switch(bpp) {
  case 1:
    *p = pixel;
    break;
  case 2:
    *(Uint16 *)p = pixel;
    break;
  case 3:
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
      p[0] = (pixel >> 16) & 0xff;
      p[1] = (pixel >> 8) & 0xff;
      p[2] = pixel & 0xff;
#else
      p[0] = pixel & 0xff;
      p[1] = (pixel >> 8) & 0xff;
      p[2] = (pixel >> 16) & 0xff;
#endif
    break;
  case 4:
    *(Uint32 *)p = pixel;
    break;
  }
}

void f437_Update(FAKE437 *fake437){
  int x;
  int y;
  int r;
  int c;
  int i;
  unsigned int hex;
  Uint32 fg;
  Uint32 bg;
  SDL_Color *color;
  char *ch;
  char fragment[2] = "\0\0";
  Sint16 offsetx;
  Sint16 offsety;
  f437_GetOffsets(fake437, &offsetx, &offsety);
  if(SDL_MUSTLOCK(fake437->surface)) SDL_LockSurface(fake437->surface);
  for(y = 0 ; y < fake437->height ; y++)
    for(x = 0 ; x < fake437->width ; x++)
      if(F437_DIRTY(fake437, x, y)){
	F437_DIRTY(fake437, x, y) = 0;
	color = &(fake437->colors[fake437->cells
				  [F437_INDEX(fake437, x, y)].fg]);
	fg = SDL_MapRGB(fake437->surface->format, color->r, color->g, color->b);
	color = &(fake437->colors[fake437->cells
				  [F437_INDEX(fake437, x, y)].bg]);
	bg = SDL_MapRGB(fake437->surface->format, color->r, color->g, color->b);
	ch = fake437->chars[fake437->cells[F437_INDEX(fake437, x, y)].ch];
	for(r = 0 ; r < F437_CHAR_HEIGHT ; r++)
	  for(c = 0 ; c < F437_CHAR_WIDTH / 4 ; c++){
	    fragment[0] = ch[r*2 + c];
	    sscanf(fragment, "%X", &hex);
	    for(i = 0 ; i < 4 ; i++)
	      if((1 << (3 - i)) & hex) putpixel(fake437->surface,
					  offsetx + x*F437_CHAR_WIDTH + c*4 + i,
					  offsety + y*F437_CHAR_HEIGHT + r,
					  fg);
	      else putpixel(fake437->surface,
			    offsetx + x*F437_CHAR_WIDTH + c*4 + i,
			    offsety + y*F437_CHAR_HEIGHT + r,
			    bg);
	  }
      }
  if(SDL_MUSTLOCK(fake437->surface)) SDL_UnlockSurface(fake437->surface);
}

SDL_Rect *f437_GetDirtyRects(FAKE437 *fake437, int *numrects){
  int x;
  int y;
  int rect = 0;
  SDL_Rect *rects;
  Sint16 offsetx;
  Sint16 offsety;
  f437_GetOffsets(fake437, &offsetx, &offsety);
  *numrects = 0;
  for(y = 0 ; y < fake437->height ; y++)
    for(x = 0 ; x < fake437->width ; x++)
      if(F437_DIRTY(fake437, x, y)) (*numrects)++;
  if((rects = calloc(*numrects, sizeof(SDL_Rect))) == NULL) return NULL;
  for(y = 0 ; y < fake437->height ; y++)
    for(x = 0 ; x < fake437->width ; x++)
      if(F437_DIRTY(fake437, x, y)){
	rects[rect].x = offsetx + x * F437_CHAR_WIDTH;
	rects[rect].y = offsety + y * F437_CHAR_HEIGHT;
	rects[rect].w = F437_CHAR_WIDTH;
	rects[rect].h = F437_CHAR_HEIGHT;
	rect++;
      }
  return rects;
}
